package gogs_hook

import (
	"time"

	"atomgit.com/openlinksaas-org/proto-gen-go.git/events/events_gogs"
)

type Permission struct {
	Admin bool `json:"admin"`
	Push  bool `json:"push"`
	Pull  bool `json:"pull"`
}

func (item *Permission) ToProtoBuf() *events_gogs.Permission {
	return &events_gogs.Permission{
		Admin: item.Admin,
		Push:  item.Push,
		Pull:  item.Pull,
	}
}

type User struct {
	Id        int64  `json:"id"`
	UserName  string `json:"username"`
	Login     string `json:"login"`
	FullName  string `json:"full_name"`
	Email     string `json:"email"`
	AvatarUrl string `json:"avatar_url"`
}

func (item *User) ToProtoBuf() *events_gogs.User {
	return &events_gogs.User{
		Id:        item.Id,
		UserName:  item.UserName,
		Login:     item.Login,
		FullName:  item.FullName,
		Email:     item.Email,
		AvatarUrl: item.AvatarUrl,
	}
}

type Repository struct {
	Id            int64       `json:"id"`
	Owner         *User       `json:"owner"`
	Name          string      `json:"name"`
	FullName      string      `json:"full_name"`
	Description   string      `json:"description"`
	Private       bool        `json:"private"`
	Unlisted      bool        `json:"unlisted"`
	Fork          bool        `json:"fork"`
	Parent        *Repository `json:"parent"`
	Empty         bool        `json:"empty"`
	Mirror        bool        `json:"mirror"`
	Size          int64       `json:"size"`
	HtmlUrl       string      `json:"html_url"`
	SshUrl        string      `json:"ssh_url"`
	CloneUrl      string      `json:"clone_url"`
	Website       string      `json:"website"`
	Stars         int         `json:"stars_count"`
	Forks         int         `json:"forks_count"`
	Watchers      int         `json:"watchers_count"`
	OpenIssues    int         `json:"open_issues_count"`
	DefaultBranch string      `json:"default_branch"`
	Created       string      `json:"created_at"`
	Updated       string      `json:"updated_at"`
	Permissions   *Permission `json:"permissions,omitempty"`
}

func (item *Repository) ToProtoBuf() *events_gogs.Repository {
	ret := &events_gogs.Repository{
		Id:            item.Id,
		Owner:         []*events_gogs.User{},
		Name:          item.Name,
		FullName:      item.FullName,
		Description:   item.Description,
		PrivateFlag:   item.Private,
		Unlisted:      item.Unlisted,
		Fork:          item.Fork,
		Parent:        []*events_gogs.Repository{},
		Empty:         item.Empty,
		Mirror:        item.Mirror,
		Size:          item.Size,
		HtmlUrl:       item.HtmlUrl,
		SshUrl:        item.SshUrl,
		CloneUrl:      item.CloneUrl,
		Website:       item.Website,
		Stars:         int32(item.Stars),
		Forks:         int32(item.Forks),
		Watchers:      int32(item.Watchers),
		OpenIssues:    int32(item.OpenIssues),
		DefaultBranch: item.DefaultBranch,
		Created:       item.Created,
		Updated:       item.Updated,
		Permissions:   []*events_gogs.Permission{},
	}
	if item.Owner != nil {
		ret.Owner = append(ret.Owner, item.Owner.ToProtoBuf())
	}
	if item.Parent != nil {
		ret.Parent = append(ret.Parent, item.Parent.ToProtoBuf())
	}
	if item.Permissions != nil {
		ret.Permissions = append(ret.Permissions, item.Permissions.ToProtoBuf())
	}
	return ret
}

type Label struct {
	Id    int64  `json:"id"`
	Name  string `json:"name"`
	Color string `json:"color"`
	Url   string `json:"url"`
}

func (item *Label) ToProtoBuf() *events_gogs.Label {
	return &events_gogs.Label{
		Id:    item.Id,
		Name:  item.Name,
		Color: item.Color,
		Url:   item.Url,
	}
}

type Milestone struct {
	Id           int64   `json:"id"`
	Title        string  `json:"title"`
	Description  string  `json:"description"`
	State        string  `json:"state"`
	OpenIssues   int     `json:"open_issues"`
	ClosedIssues int     `json:"closed_issues"`
	Closed       *string `json:"closed_at"`
	Deadline     *string `json:"due_on"`
}

func (item *Milestone) ToProtoBuf() *events_gogs.Milestone {
	ret := &events_gogs.Milestone{
		Id:           item.Id,
		Title:        item.Title,
		Description:  item.Description,
		State:        item.State,
		OpenIssues:   int32(item.OpenIssues),
		ClosedIssues: int32(item.ClosedIssues),
		Closed:       []string{}, //XXX
		Deadline:     []string{}, //XXX
	}
	if item.Closed != nil && *item.Closed != "" {
		ret.Closed = append(ret.Closed, *item.Closed)
	}
	if item.Deadline != nil && *item.Deadline != "" {
		ret.Deadline = append(ret.Deadline, *item.Deadline)
	}
	return ret
}

type PullRequestMeta struct {
	HasMerged bool    `json:"merged"`
	Merged    *string `json:"merged_at"`
}

func (item *PullRequestMeta) ToProtoBuf() *events_gogs.PullRequestMeta {
	ret := &events_gogs.PullRequestMeta{
		HasMerged: item.HasMerged,
		Merged:    []string{},
	}
	if item.Merged != nil && *item.Merged != "" {
		ret.Merged = append(ret.Merged, *item.Merged)
	}
	return ret
}

type Issue struct {
	Id        int64      `json:"id"`
	Index     int64      `json:"number"`
	Poster    *User      `json:"user"`
	Title     string     `json:"title"`
	Body      string     `json:"body"`
	Labels    []*Label   `json:"labels"`
	Milestone *Milestone `json:"milestone"`
	Assignee  *User      `json:"assignee"`
	State     string     `json:"state"`
	Comments  int        `json:"comments"`
	Created   string     `json:"created_at"`
	Updated   string     `json:"updated_at"`

	PullRequest *PullRequestMeta `json:"pull_request"`
}

func (item *Issue) ToProtoBuf() *events_gogs.Issue {
	ret := &events_gogs.Issue{
		Id:          item.Id,
		Index:       item.Index,
		Poster:      []*events_gogs.User{},
		Title:       item.Title,
		Body:        item.Body,
		Labels:      []*events_gogs.Label{},
		Milestone:   []*events_gogs.Milestone{},
		Assignee:    []*events_gogs.User{},
		State:       item.State,
		Comments:    int32(item.Comments),
		Created:     item.Created, //XXX ,timestamp?
		Updated:     item.Updated, //XXX,timestamp?
		PullRequest: []*events_gogs.PullRequestMeta{},
	}
	if item.Poster != nil {
		ret.Poster = append(ret.Poster, item.Poster.ToProtoBuf())
	}
	if item.Labels != nil {
		for _, label := range item.Labels {
			if label != nil {
				ret.Labels = append(ret.Labels, label.ToProtoBuf())
			}
		}

	}
	if item.Milestone != nil {
		ret.Milestone = append(ret.Milestone, item.Milestone.ToProtoBuf())
	}
	if item.Assignee != nil {
		ret.Assignee = append(ret.Assignee, item.Assignee.ToProtoBuf())
	}
	if item.PullRequest != nil {
		ret.PullRequest = append(ret.PullRequest, item.PullRequest.ToProtoBuf())
	}
	return ret
}

type Comment struct {
	Id      int64  `json:"id"`
	HtmlUrl string `json:"html_url"`
	Poster  *User  `json:"user"`
	Body    string `json:"body"`
	Created string `json:"created_at"`
	Updated string `json:"updated_at"`
}

func (item *Comment) ToProtoBuf() *events_gogs.Comment {
	ret := &events_gogs.Comment{
		Id:      item.Id,
		HtmlUrl: item.HtmlUrl,
		Poster:  []*events_gogs.User{},
		Body:    item.Body,
		Created: item.Created,
		Updated: item.Updated,
	}
	if item.Poster != nil {
		ret.Poster = append(ret.Poster, item.Poster.ToProtoBuf())
	}
	return ret
}

type ChangesFrom struct {
	From string `json:"from"`
}

func (item *ChangesFrom) ToProtoBuf() *events_gogs.ChangesFrom {
	return &events_gogs.ChangesFrom{
		FromValue: item.From,
	}
}

type Changes struct {
	Title *ChangesFrom `json:"title,omitempty"`
	Body  *ChangesFrom `json:"body,omitempty"`
}

func (item *Changes) ToProtoBuf() *events_gogs.Changes {
	ret := &events_gogs.Changes{
		Title: []*events_gogs.ChangesFrom{},
		Body:  []*events_gogs.ChangesFrom{},
	}
	if item.Title != nil {
		ret.Title = append(ret.Title, item.Title.ToProtoBuf())
	}
	if item.Body != nil {
		ret.Body = append(ret.Body, item.Body.ToProtoBuf())
	}
	return ret
}

type PullRequest struct {
	Id        int64      `json:"id"`
	Index     int64      `json:"number"`
	Poster    *User      `json:"user"`
	Title     string     `json:"title"`
	Body      string     `json:"body"`
	Labels    []*Label   `json:"labels"`
	Milestone *Milestone `json:"milestone"`
	Assignee  *User      `json:"assignee"`
	State     string     `json:"state"`
	Comments  int        `json:"comments"`

	HeadBranch string      `json:"head_branch"`
	HeadRepo   *Repository `json:"head_repo"`
	BaseBranch string      `json:"base_branch"`
	BaseRepo   *Repository `json:"base_repo"`

	HtmlUrl string `json:"html_url"`

	Mergeable      *bool   `json:"mergeable"`
	HasMerged      bool    `json:"merged"`
	Merged         *string `json:"merged_at"`
	MergedCommitId *string `json:"merge_commit_sha"`
	MergedBy       *User   `json:"merged_by"`
}

func (item *PullRequest) ToProtoBuf() *events_gogs.PullRequest {
	ret := &events_gogs.PullRequest{
		Id:             item.Id,
		Index:          item.Index,
		Poster:         []*events_gogs.User{},
		Title:          item.Title,
		Body:           item.Body,
		Labels:         []*events_gogs.Label{},
		Milestone:      []*events_gogs.Milestone{},
		Assignee:       []*events_gogs.User{},
		State:          item.State,
		Comments:       int32(item.Comments),
		HeadBranch:     item.HeadBranch,
		HeadRepo:       []*events_gogs.Repository{},
		BaseBranch:     item.BaseBranch,
		BaseRepo:       []*events_gogs.Repository{},
		HtmlUrl:        item.HtmlUrl,
		Mergeable:      []bool{},
		HasMerged:      item.HasMerged,
		Merged:         []string{},
		MergedCommitId: []string{},
		MergedBy:       []*events_gogs.User{},
	}
	if item.Poster != nil {
		ret.Poster = append(ret.Poster, item.Poster.ToProtoBuf())
	}
	if item.Labels != nil {
		for _, label := range item.Labels {
			if label != nil {
				ret.Labels = append(ret.Labels, label.ToProtoBuf())
			}
		}
	}
	if item.Milestone != nil {
		ret.Milestone = append(ret.Milestone, item.Milestone.ToProtoBuf())
	}
	if item.Assignee != nil {
		ret.Assignee = append(ret.Assignee, item.Assignee.ToProtoBuf())
	}
	if item.HeadRepo != nil {
		ret.HeadRepo = append(ret.HeadRepo, item.HeadRepo.ToProtoBuf())
	}
	if item.BaseRepo != nil {
		ret.BaseRepo = append(ret.BaseRepo, item.BaseRepo.ToProtoBuf())
	}
	if item.Mergeable != nil {
		ret.Mergeable = append(ret.Mergeable, *item.Mergeable)
	}
	if item.MergedCommitId != nil && *item.MergedCommitId != "" {
		ret.MergedCommitId = append(ret.MergedCommitId, *item.MergedCommitId)
	}
	if item.MergedBy != nil {
		ret.MergedBy = append(ret.MergedBy, item.MergedBy.ToProtoBuf())
	}
	return ret
}

type CommitUser struct {
	Name     string `json:"name"`
	Email    string `json:"email"`
	UserName string `json:"username"`
}

func (item *CommitUser) ToProtoBuf() *events_gogs.CommitUser {
	return &events_gogs.CommitUser{
		Name:     item.Name,
		Email:    item.Email,
		UserName: item.UserName,
	}
}

type Commit struct {
	Id        string      `json:"id"`
	Message   string      `json:"message"`
	Url       string      `json:"url"`
	Author    *CommitUser `json:"author"`
	Committer *CommitUser `json:"committer"`

	Added    []string `json:"added"`
	Removed  []string `json:"removed"`
	Modified []string `json:"modified"`

	Timestamp string `json:"timestamp"`
}

func (item *Commit) ToProtoBuf() *events_gogs.Commit {
	ret := &events_gogs.Commit{
		Id:        item.Id,
		Message:   item.Message,
		Url:       item.Url,
		Author:    []*events_gogs.CommitUser{},
		Committer: []*events_gogs.CommitUser{},
		Added:     []string{},
		Removed:   []string{},
		Modified:  []string{},
	}
	if item.Author != nil {
		ret.Author = append(ret.Author, item.Author.ToProtoBuf())
	}
	if item.Committer != nil {
		ret.Committer = append(ret.Committer, item.Committer.ToProtoBuf())
	}
	if item.Added != nil {
		ret.Added = append(ret.Added, item.Added...)
	}
	if item.Removed != nil {
		ret.Removed = append(ret.Removed, item.Removed...)
	}
	if item.Modified != nil {
		ret.Modified = append(ret.Modified, item.Modified...)
	}
	ts, err := time.Parse(time.RFC3339, item.Timestamp)
	if err == nil {
		ret.Timestamp = ts.UnixNano() / 1e6
	}
	return ret
}

type Release struct {
	Id              int64  `json:"id"`
	TagName         string `json:"tag_name"`
	TargetCommitish string `json:"target_commitish"`
	Name            string `json:"name"`
	Body            string `json:"body"`
	Draft           bool   `json:"draft"`
	Prerelease      bool   `json:"prerelease"`
	Author          *User  `json:"author"`
	Created         string `json:"created_at"`
}

func (item *Release) ToProtoBuf() *events_gogs.Release {
	ret := &events_gogs.Release{
		Id:              item.Id,
		TagName:         item.TagName,
		TargetCommitish: item.TargetCommitish,
		Name:            item.Name,
		Body:            item.Body,
		Draft:           item.Draft,
		Prerelease:      item.Prerelease,
		Author:          []*events_gogs.User{},
		Created:         item.Created,
	}
	if item.Author != nil {
		ret.Author = append(ret.Author, item.Author.ToProtoBuf())
	}
	return ret
}
